<template>
    <div class="content" ref="content" id="content">
        <!-- <div class="panel" style="position: absolute; z-index: 99999;">
            <el-button v-if="!isGoBack" type="primary" plain @click="startCruise">开始巡航</el-button>
            <el-button v-if="!isGoBack" type="primary" plain @click="pauseCruise">暂停巡航</el-button>
            <el-button type="primary" v-if="isGoBack || isCruise != ''" plain @click="goBack">返回</el-button>
            <el-button type="primary" plain @click="toggle">全屏</el-button>
            <el-button type="primary" plain @click="customLine">自定义路线</el-button>
            <el-button type="primary" plain @click="addLine">添加路线</el-button>
            <el-button type="primary" plain @click="removeLine">删除路线</el-button>
        </div> -->

        <!-- <Loading v-if="!loadingPercentage.completed" size="220" color="#03b2c9" :text="loadingPercentage.percentage"
            dot-count="6" /> -->
        <div ref="container" class="three-container"></div>
    </div>
</template>

<script setup async>
import { ref, onMounted, onBeforeUnmount, shallowRef, defineEmits, defineProps } from 'vue'
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass'
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader'
import { OutputPass } from 'three/examples/jsm/postprocessing/OutputPass'
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
import { CSS2DRenderer, CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer"
import { gsap } from 'gsap'
import { createBoundingPlanes } from '@/utils/three/BoundingPlanesGroup'
import Loading from '@/components/Loading'
import { useFullscreen } from '@vueuse/core'
import particleFire from 'three-particle-fire';
import { LineBuffer } from '@/utils/three/LineBuffre.js';
import { SplineEditor } from '@/utils/three/SplineEditor.js'

import textBackground from '@/assets/three/text-bac.svg';
import lineBackground from '@/assets/three/line.svg';
import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';

const props = defineProps({
    outlinePass: {
        type: true
    }
})
const emit = defineEmits(['loadingFinish']);
// DOM 引用
const container = ref(null)
const containerOffsetLeft = ref('100px');
const containerOffsetTop = ref('85px');

const content = ref(null)
const { toggle } = useFullscreen(content)

// 状态管理
const isGoBack = ref(false)
const isCruise = ref('')
const loadingPercentage = ref({
    percentage: '',
    completed: false
})

// Three.js 核心对象
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 70000)
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

let renderer = null;
let controls = null;
let composer = null;
let css2Renderer = null;
const gltfGroup = new THREE.Group()
const css2dRendererGroup = new THREE.Group()
const boundingPlanesGroup = new THREE.Group()
const fireGroup = new THREE.Group()
let particleFireMesh, outlinePass, splineEditor, activeModel;

// 巡航路径
let linePoints = [];
let curve = new THREE.CatmullRomCurve3(linePoints);


// 资源管理
const resources = {
    textures: [],
    models: [],
    geometries: [],
    materials: [],
    eventListeners: [],
    animations: []
}

defineExpose([
    scene,
    camera,
    renderer,
])
// 模型配置
const gltfArray = [
    // { url: '/model/石带水厂输水管/石带水厂输水管_result-0.gltf', labelText: '', isBbox: false },
    // { url: '/newgltf/场地带门卫室/场地带门卫室_result-1.gltf', labelText: '', isBbox: false , sg: true },
    // { url: '/newgltf/场地带门卫室/场地带门卫室_result-0.gltf', labelText: '', isBbox: false, sg: true },
    // { url: '/newgltf/GLTF/机修间/机修间_result-0.gltf', labelText: '机修间', isBbox: false },
    // { url: '/newgltf/GLTF/加药间/加药间_result-0.gltf', labelText: '加药间', isBbox: false },
    // { url: '/newgltf/GLTF/排泥池/排泥池_result-0.gltf', labelText: '排泥池', isBbox: false },
    // { url: '/newgltf/GLTF/平衡池/平衡池_result-0.gltf', labelText: '平衡池', isBbox: false },
    // { url: '/newgltf/GLTF/平流沉淀池/平流沉淀池_result-0.gltf', labelText: '沉淀池', isBbox: false },
    // { url: '/newgltf/GLTF/清水池/清水池_result-0.gltf', labelText: '清水池', isBbox: false },
    // { url: '/newgltf/GLTF/食堂/食堂_result-0.gltf', labelText: '食堂', isBbox: false },
    // { url: '/newgltf/GLTF/脱水机房/脱水机房_result-0.gltf', labelText: '脱水机房', isBbox: false },
    // { url: '/newgltf/GLTF/污泥浓缩池/污泥浓缩池_result-0.gltf', labelText: '污泥浓缩池', isBbox: false },
    // { url: '/newgltf/GLTF/V型滤池/V型滤池_result-0.gltf', labelText: 'V型滤池', isBbox: false },
    // { url: '/newgltf/GLTF/工作管理间/工作管理间_result-0.gltf', labelText: '工作管理间', isBbox: false },
    // { url: '/newgltf/GLTF/石带水厂土建模型03【链接版】/石带水厂土建模型03【链接版】_result-0.gltf', labelText: '', isBbox: false },
    // { url: '/newgltf/GLTF/石带水厂土建模型03【链接版】/石带水厂土建模型03【链接版】_result-1.gltf', labelText: '', isBbox: false },
    // { url: '/newgltf/GLTF/石带水厂土建模型03【链接版】/石带水厂土建模型03【链接版】_result-2.gltf', labelText: '', isBbox: false },
    // { url: '/newgltf/GLTF/石带水厂土建模型03【链接版】/石带水厂土建模型03【链接版】_result-3.gltf', labelText: '', isBbox: false },
    // { url: '/newgltf/GLTF/石带水厂土建模型03【链接版】/石带水厂土建模型03【链接版】_result-4.gltf', labelText: '', isBbox: false },
    // { url: '/newgltf/GLTF/石带水厂土建模型03【链接版】/石带水厂土建模型03【链接版】_result-5.gltf', labelText: '', isBbox: false },
    { url: '/newgltf/GLTF/石带水厂土建模型03【链接版】/石带水厂土建模型03【链接版】_result-5.gltf', labelText: '', isBbox: false },

]

let lineBuffreMesh, lineBuffer;
// 加载管理器
const loadingManager = new THREE.LoadingManager(
    () => {
        loadingPercentage.value.completed = true;
        emit('loadingFinish', scene);
        resources.animations.push(
            gsap.to(camera.position, {
                y: 90,
                z: 90,
                duration: 1.5,
                delay: 0.5
            })
        )
    },
    (url, loaded, total) => {
        loadingPercentage.value.percentage = `加载中..${((loaded / total) * 100).toFixed(2)}%`
    }
)

// 
const addLine = () => {
    splineEditor.addPoint(new THREE.Vector3(Math.random() * 160 - 80, 0.5, Math.random() * 80 - 40));
}
const removeLine = () => {
    splineEditor.removePoint();
}
const customLine = () => {
    lineBuffer?.dispose();
    scene.remove(lineBuffreMesh);

    // 创建编辑器实例
    splineEditor = new SplineEditor({
        container: container.value,
        scene,
        camera,
        renderer,
        controls,
        initialPositions: [
            new THREE.Vector3(-78.55469938835896, 0.5, -39.0738157017361),
            new THREE.Vector3(9.917643025073888, 0.5, -37.70185611779522),
            new THREE.Vector3(12.132305920892101, 0.5, 26.449312653731752),
            new THREE.Vector3(61.194911395541574, 0.5, 25.825519784481294)
        ]
    });
}




const initParticleFire = (position, name) => {

    let fireHeight = 22000;
    let particleCount = 2000;

    let geometry0 = new particleFire.Geometry(7000, fireHeight, particleCount);
    let material0 = new particleFire.Material({ color: 0xff2200, size: 6000, depthTest: false, depthWrite: false });
    material0.setPerspective(camera.fov, window.innerHeight);
    particleFireMesh = new THREE.Points(geometry0, material0);
    particleFireMesh.position.copy(position);
    particleFireMesh.resetName = name;
    fireGroup.add(particleFireMesh);
}

const createLineCallBack = () => {
    isCruise.value = 'start';
}

const createLine = () => {
    let params = {
        path: linePoints, point: 2000, pointsScale: 2, callback: createLineCallBack
    }
    const texture = new THREE.TextureLoader().load("/three/right.png");
    texture.wrapS = texture.wrapT = THREE.RepeatWrapping;

    // 创建线缓冲对象
    lineBuffer = new LineBuffer(params);
    // 创建材质
    const material = new THREE.ShaderMaterial({
        uniforms: {
            uTime: {
                value: 0
            },
            uColor: {
                value: new THREE.Color(0xff2200)
            },
            uJtou: {
                value: texture
            }
        },
        side: THREE.DoubleSide,
        depthTest: false,
        depthWrite: false,
        vertexShader: `
            varying vec2 vUv;
            varying vec3 v_position;

            void main() {
                vUv = uv;
                v_position =  position;

                vec4 modelPosition = modelMatrix * vec4( position, 1.0 );
                gl_Position = projectionMatrix * viewMatrix * modelPosition;
            }
         `,
        transparent: true,
        // blending :THREE.AdditiveBlending,
        fragmentShader: `
            varying vec2 vUv;
            varying vec3 v_position;
            uniform sampler2D uJtou;
            uniform float uTime;
            uniform vec3 uColor;
            void main() {
                vec2 vuv = vUv;
                vec4 udiColor = texture2D(uJtou,vec2((vuv.x * 60.2) - (uTime * 0.2),vuv.y));
                // gl_FragColor = mix(vec4(0.0),vec4(uColor,1.0),abs(vUv.y  - 0.5)+0.2);
                gl_FragColor = vec4(uColor, udiColor.a);
            }
        `
    })

    // 创建带有动画的网格
    lineBuffreMesh = lineBuffer.createAnimatedMesh(material);
    scene.add(lineBuffreMesh);

    // 播放生长动画
    lineBuffer.animateGrowth(5);
}
// 初始化场景
const initScene = async () => {

    // 初始化渲染器
    renderer = new THREE.WebGLRenderer({
        antialias: true,
        logarithmicDepthBuffer: true
    })
    updateRendererSize()
    container.value.appendChild(renderer.domElement)
    // renderer.toneMappingExposure = 0.3
    // 或者使用环境光
    // 4. 添加光照
    scene.add(new THREE.AmbientLight(0x404040, 43.5));
    const directionalLight = new THREE.DirectionalLight(0x404040, 5);
    directionalLight.position.set(50, 100, 50);
    scene.add(directionalLight);
    const directionalLight1 = new THREE.DirectionalLight(0x404040, 5);
    directionalLight1.position.set(-50, -100, -50);
    scene.add(directionalLight1);
    // const axesHelper = new THREE.AxesHelper(1000000);
    // scene.add(axesHelper);
    // 设置相机
    camera.position.set(0, 200, 200)
    camera.updateProjectionMatrix()

    // 初始化控制器
    controls = new OrbitControls(camera, renderer.domElement)
    controls.enableDamping = true

    
    renderer.physicallyCorrectLights = true;
    renderer.outputEncoding = THREE.sRGBEncoding;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;

    // 设置场景背景
    scene.background = new THREE.Color('#02004d')

    // 初始化后期处理和标签渲染器
    initPostProcessing()
    createCSS2DRenderer()

    // 加载模型和环境
    gltfArray.forEach((item) => {
        loadModel(item)
    })
    loadEnvironment()

    scene.add(gltfGroup)
    scene.add(css2dRendererGroup)
    scene.add(boundingPlanesGroup)
    scene.add(fireGroup)




}

// 创建标签
const createLabel = (text) => {
    const label = document.createElement("div")
    label.style.cursor = 'pointer';
    label.style.pointerEvents = 'auto';
    label.innerHTML = `
        <div style="display: flex;align-items: center;flex-direction: column;justify-content: center;">
            <div style="width:120px;height: 50px;position: relative;">
                <img src="${textBackground}" style="width:120px;height: 50px;" />
                <div class="label-text" style="position:absolute;top:11.5px;left:0;right:0;margin: 0 auto;text-align: center;color:#fff;">${text}</div>    
            </div>
            <img src="${lineBackground}" style="width: 3px;height: 40px;margin-top: -5px;" />    
        </div>
    `
    return label
}

// 创建CSS2D渲染器
const createCSS2DRenderer = () => {
    css2Renderer = new CSS2DRenderer()
    updateCSS2DRendererSize()
    css2Renderer.domElement.style.position = 'absolute'
    css2Renderer.domElement.style.top = '0'
    css2Renderer.domElement.style.pointerEvents = 'none'
    container.value.appendChild(css2Renderer.domElement)
}

// 初始化后期处理
const initPostProcessing = () => {
    composer = new EffectComposer(renderer)
    composer.addPass(new RenderPass(scene, camera))

    const fxaaPass = new ShaderPass(FXAAShader)
    const pixelRatio = renderer.getPixelRatio()
    fxaaPass.material.uniforms['resolution'].value.x = 1 / (container.value.clientWidth * pixelRatio)
    fxaaPass.material.uniforms['resolution'].value.y = 1 / (container.value.clientHeight * pixelRatio)
    composer.addPass(fxaaPass)
    composer.addPass(new OutputPass())

    if (props.outlinePass) {
        // 4. 创建描边效果
        outlinePass = new OutlinePass(
            new THREE.Vector2(container.value.clientWidth, container.value.clientHeight),
            scene,
            camera
        );
        outlinePass.edgeStrength = 3.0; // 描边强度
        outlinePass.edgeGlow = 0.5;     // 边缘发光
        outlinePass.edgeThickness = 1.0; // 边缘厚度
        outlinePass.pulsePeriod = 2;    // 脉冲周期
        outlinePass.visibleEdgeColor.set('#ff0000'); // 可见边颜色
        outlinePass.hiddenEdgeColor.set('#ff0000');  // 隐藏边颜色
        composer.addPass(outlinePass);
        window.addEventListener('mousemove', onMouseMove);
    }
}


function onMouseMove(event) {
    // 获取容器相对于视口的坐标位置
    const rect = container.value.getBoundingClientRect();

    // 计算容器内的相对鼠标坐标 (考虑滚动偏移)
    const mouseX = event.clientX - rect.left;
    const mouseY = event.clientY - rect.top;

    // 转换为标准化设备坐标 (NDC: -1到1)
    mouse.x = (mouseX / rect.width) * 2 - 1;
    mouse.y = -(mouseY / rect.height) * 2 + 1;

    // 更新射线检测
    raycaster.setFromCamera(mouse, camera);
    const intersects = raycaster.intersectObjects(scene.children);

    // 更新描边对象
    outlinePass.selectedObjects = intersects.length > 0 ? [intersects[0].object] : [];
}


// 加载环境贴图
const loadEnvironment = () => {
    const hdrLoader = new RGBELoader()
    hdrLoader.load('/golden_gate_hills_4k.hdr', (texture) => {
        texture.mapping = THREE.EquirectangularReflectionMapping
        scene.environment = texture
        resources.textures.push(texture)
    })
}

// 加载模型
const loadModel = ({ url, labelText, isBbox, sg }) => {
    // const loader = new GLTFLoader(loadingManager)
    // const dracoLoader = new DRACOLoader()
    // dracoLoader.setDecoderPath("/draco/gltf/")
    // dracoLoader.setDecoderConfig({ type: "js" })
    // loader.setDRACOLoader(dracoLoader)
    // loader.load(url, (gltf) => {
    //     const model = gltf.scene
    //     resources.models.push(model)
    //     // model.scale.set(0.001, 0.001, 0.001)
    //     model.traverse((item) => {
    //         if (item.type == 'Mesh') {
    //             // item.material.transparent = true
    //         }
    //     })
    //     if (sg) {
    //         model.rotation.y += Math.PI / 4.9;
    //     }
    //     if (labelText) {
    //         const box = new THREE.Box3().setFromObject(model)
    //         const center = box.getCenter(new THREE.Vector3())
    //         const div = createLabel(labelText)
    //         const clickHandler = () => LabelClick(model, labelText)
    //         div.addEventListener('click', clickHandler)
    //         resources.eventListeners.push({ element: div, handler: clickHandler })
    //         const labelObject = new CSS2DObject(div)
    //         labelObject.position.set(center.x, box.max.y, center.z)
    //         labelObject.center.set(0.5, 1);
    //         labelObject.resetName = labelText
    //         css2dRendererGroup.add(labelObject)
    //         resources.models.push(labelObject)
    //     }
    //     if (isBbox) {
    //         const bbox = new THREE.Box3().setFromObject(model)
    //         const center = bbox.getCenter(new THREE.Vector3())
    //         const boundingPlanes = createBoundingPlanes(bbox)
    //         boundingPlanes.resetName = labelText;
    //         boundingPlanesGroup.add(boundingPlanes);
    //         resources.models.push(boundingPlanes)
    //         initParticleFire(new THREE.Vector3(center.x, center.y + 12000, center.z), labelText);
    //     }
    //     model.resetName = labelText
    //     gltfGroup.add(model)
    // }, (error) => {
    // })

    const fbxload = new FBXLoader();


    fbxload.load('/wlsc_cdn.FBX', (fbx) => {
        scene.add(fbx)
        fbx.traverse((item) => {
            console.log(item);
            if (item.type == 'Mesh') {
                item.material.transparent = true;
                item.material.side = THREE.DoubleSide;

            }
        })
    })
}

// 标签点击事件
const LabelClick = (model, labelText) => {
    setCameraTarget(model)
    toggleModelVisibility(labelText)
    isGoBack.value = true
}

// 设置相机目标
const setCameraTarget = (model) => {
    // 然后恢复时这样操作
    // 首先确保正确保存原始颜色
    model.traverse((item) => {
        if (item.type == 'Mesh') {
            item.material.transparent = true;
            item.material.side = THREE.DoubleSide;

            // 确保保存原始颜色（使用clone创建新实例）
            if (!item.material.oldColor) {
                item.material.oldColor = item.material.color.clone();
            }

            item.material.color.set(0x00ffff);
            item.material.opacity = 0.05;
        }
    });

    activeModel = model;
    const box = new THREE.Box3().setFromObject(model)
    const center = box.getCenter(new THREE.Vector3())
    const size = box.getSize(new THREE.Vector3())

    const targetPosition = new THREE.Vector3(
        center.x + size.length() * 0.2,
        center.y + size.length() * 0.5,
        center.z + size.length()
    )

    resources.animations.push(
        gsap.timeline()
            .to(camera.position, {
                x: targetPosition.x,
                y: targetPosition.y,
                z: targetPosition.z,
                duration: 1.5,
                ease: "power2.inOut",
            })
            .to(controls.target, {
                x: center.x,
                y: center.y,
                z: center.z,
                duration: 0.8,
                ease: "power2.inOut",
            }, "<")
    )
}
const setVisibility = (group, visibleName) => {
    group.children.forEach(child => {
        child.visible = child.resetName === visibleName
    })
}
// 切换模型可见性
const toggleModelVisibility = (visibleName) => {
    setVisibility(gltfGroup, visibleName)
    setVisibility(css2dRendererGroup, visibleName)
    setVisibility(boundingPlanesGroup, visibleName)
    setVisibility(fireGroup, visibleName)
}

// 更新渲染器尺寸
const updateRendererSize = () => {
    if (!container.value) return

    const width = container.value.clientWidth
    const height = container.value.clientHeight

    camera.aspect = width / height
    camera.updateProjectionMatrix()
    renderer?.setSize(width, height)

    // 更新后期处理器
    if (composer) {
        composer.setSize(width, height)
        const passes = composer.passes
        for (let i = 0; i < passes.length; i++) {
            if (passes[i] instanceof ShaderPass && passes[i].material.uniforms['resolution']) {
                const pixelRatio = renderer.getPixelRatio()
                passes[i].material.uniforms['resolution'].value.x = 1 / (width * pixelRatio)
                passes[i].material.uniforms['resolution'].value.y = 1 / (height * pixelRatio)
            }
        }
    }
}

// 更新CSS2D渲染器尺寸
const updateCSS2DRendererSize = () => {
    if (!container.value || !css2Renderer) return
    const width = container.value.clientWidth
    const height = container.value.clientHeight
    css2Renderer.setSize(width, height)
}

// 巡航控制
const startCruise = () => {
    if (isCruise.value === 'start') return
    if (!lineBuffreMesh) {
        const [positons] = splineEditor.getPositions();
        splineEditor.dispose();
        linePoints = positons;
        curve = new THREE.CatmullRomCurve3(positons);
        curve.curveType = 'catmullrom';
        curve.tension = 0.2;
        createLine();
    } else {
        isCruise.value = 'start';
    }
}

const pauseCruise = () => {
    isCruise.value = 'pause'
}

// 返回初始视图
const goBack = () => {
    isGoBack.value = false
    isCruise.value = ''

    // 显示所有模型
    gltfGroup.children.forEach(child => child.visible = true)
    css2dRendererGroup.children.forEach(child => child.visible = true)
    boundingPlanesGroup.children.forEach(child => child.visible = true)
    fireGroup.children.forEach(child => child.visible = true)


    // 然后恢复时这样操作
    if (activeModel) {
        activeModel.traverse((item) => {
            if (item.type == 'Mesh' && item.material.oldColor) {
                item.material.transparent = false;
                // 使用copy方法从oldColor复制值
                item.material.color.copy(item.material.oldColor);
                item.material.opacity = 1;
            }
        });
        activeModel = null
    }

    resources.animations.push(
        gsap.timeline()
            .to(camera.position, {
                x: 0,
                y: 100,
                z: 100,
                duration: 1.5,
                ease: "power2.inOut",
            })
            .to(controls.target, {
                x: 0,
                y: 0,
                z: 0,
                duration: 0.8,
                ease: "power2.inOut",
            }, "<")
    )
}

// 相机巡航动画
const pathParams = {
    t: 0,
    lookAhead: 0.05,
    speed: 0.0004
}
const yourCompletionCallback = () => {
    isCruise.value = 'pause';
}
const animateCamera = () => {
    // 1. 计算当前点和下一个目标点
    // const currentPoint = curve.getPointAt(pathParams.t);

    // const targetT = (pathParams.t + pathParams.lookAhead) % 1;
    // const targetPoint = curve.getPointAt(targetT);

    // resources.animations.push(
    //     gsap.to(camera.position, {
    //         x: currentPoint.x,
    //         y: currentPoint.y + 2,
    //         z: currentPoint.z,
    //         duration: 0.5,
    //         ease: 'none',
    //         onUpdate() {
    //             controls.target.copy(new THREE.Vector3(targetPoint.x, targetPoint.y + 2, targetPoint.z)); // 关键：看向前方路径点
    //         }
    //     })
    // )
    // // 3. 更新进度
    // pathParams.t = (pathParams.t + pathParams.speed) % 1;

    // 1. 计算当前点和下一个目标点
    const currentPoint = curve.getPointAt(pathParams.t);

    // 2. 计算目标点（确保不超过1）
    const targetT = Math.min(pathParams.t + pathParams.lookAhead, 1); // 不超过1
    const targetPoint = curve.getPointAt(targetT);

    // 3. 检查是否到达终点
    const isComplete = pathParams.t >= 1 - pathParams.speed; // 接近终点时视为完成

    if (!isComplete) {
        resources.animations.push(
            gsap.to(camera.position, {
                x: currentPoint.x,
                y: currentPoint.y + 2,
                z: currentPoint.z,
                duration: 0.5,
                ease: 'none',
                onUpdate() {
                    // 更新目标点（防止回跳）
                    const currentTargetT = Math.min(pathParams.t + pathParams.lookAhead, 1);
                    const currentTargetPoint = curve.getPointAt(currentTargetT);
                    controls.target.copy(new THREE.Vector3(
                        currentTargetPoint.x,
                        currentTargetPoint.y + 2,
                        currentTargetPoint.z
                    ));
                },
            })
        );

        // 4. 更新进度（不超过1）
        pathParams.t = Math.min(pathParams.t + pathParams.speed, 1);
    } else {
        // 已经到达终点，执行完成回调
        console.log("已到达路径终点");
        yourCompletionCallback();
    }
};

let clock = new THREE.Clock();
// 主动画循环
const animate = () => {
    if (!container.value) return

    const rect = container.value.getBoundingClientRect()
    if (rect) {
        containerOffsetLeft.value = rect.left + 'px';
        containerOffsetTop.value = rect.top + 'px';
        renderer?.setSize(rect.width, rect.height)
        camera.aspect = rect.width / rect.height
        camera.updateProjectionMatrix()
        css2Renderer?.setSize(rect.width, rect.height)
        css2Renderer?.render(scene, camera)
    }

    composer?.render()
    controls?.update();

    if (isCruise.value === 'start') {
        animateCamera()
    }
    let delta = clock.getDelta();
    fireGroup.children.forEach(child => {
        child?.material?.update(delta);
    })

    if (lineBuffreMesh) {
        lineBuffreMesh.material.uniforms.uTime.value += 0.1;
    }
    requestAnimationFrame(animate)
}

// 窗口大小变化处理
const handleResize = () => {
    updateRendererSize()
    updateCSS2DRendererSize()
}

// 组件挂载
onMounted(() => {
    try {
        particleFire?.install({ THREE: THREE });
        particleFire?.init();
    } catch (e) {
        console.log(e)
    }


    initScene()
    animate()

    window.addEventListener('resize', handleResize)
})

// 组件卸载前清理
onBeforeUnmount(() => {
    // 移除事件监听
    window.removeEventListener('resize', handleResize)
    window.removeEventListener('mousemove', onMouseMove);

    // 清理动画
    resources.animations.forEach(anim => anim.kill())

    // 清理事件监听器
    resources.eventListeners.forEach(({ element, handler }) => {
        element?.removeEventListener('click', handler)
    })

    // 清理场景
    scene.traverse(object => {
        if (!object.isMesh) return

        if (object.geometry) {
            object.geometry.dispose()
        }

        if (object.material) {
            if (Array.isArray(object.material)) {
                object.material.forEach(m => m.dispose())
            } else {
                object.material.dispose()
            }
        }
    })
    // 清理纹理
    resources.textures.forEach(texture => {
        texture.dispose()
        texture.image?.close?.()
    })

    // 清理渲染器
    if (renderer) {
        container.value?.removeChild(renderer.domElement)
        renderer.dispose()
    }

    // 清理CSS2D渲染器
    if (css2Renderer) {
        container.value?.removeChild(css2Renderer.domElement)
    }

    // 清理控制器
    controls?.dispose();

    // 清理GSAP
    gsap.globalTimeline.clear();


})
</script>

<style scoped lang="scss">
.three-container {
    width: calc(100vw - v-bind(containerOffsetLeft));
    // width: calc(90.8vw) ;
    height: calc(92.5vh);
    position: relative;
    overflow: hidden;
}

.content {
    width: 100%;
    height: 100%;
    position: relative;
}
</style>